#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
昆明地铁数据分析与可视化 - 第四部分
本脚本进行高级可视化及结论分析
"""

import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.font_manager import FontProperties
import matplotlib.patches as mpatches
import warnings
import matplotlib.ticker as mticker
from pathlib import Path
import calendar
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# 忽略警告
warnings.filterwarnings('ignore')

# 设置中文字体
try:
    font = FontProperties(fname=r"C:\Windows\Fonts\SimHei.ttf")
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
except:
    print("无法加载SimHei字体，使用系统默认字体")

# 创建输出目录
output_dir = "analysis_results/kunming_analysis"
os.makedirs(output_dir, exist_ok=True)

def load_data():
    """加载清洗后的地铁数据"""
    data_dir = Path("data/processed/cleaned_data")
    
    # 加载站点数据
    print("加载站点数据...")
    stations_path = data_dir / "cleaned_stations_2024.csv"
    if not os.path.exists(stations_path):
        stations_path = data_dir / "cleaned_stations_2023.csv"
    stations_df = pd.read_csv(stations_path)
    
    # 加载线路数据
    print("加载线路数据...")
    lines_path = data_dir / "cleaned_lines_2024.csv"
    if not os.path.exists(lines_path):
        lines_path = data_dir / "cleaned_lines_2023.csv"
    lines_df = pd.read_csv(lines_path)
    
    # 加载客流量数据
    print("加载客流量数据...")
    flow_path = data_dir / "cleaned_flow_data.csv"
    flow_df = pd.read_csv(flow_path)
    
    print(f"数据加载完成！站点数据:{stations_df.shape}，线路数据:{lines_df.shape}，客流量数据:{flow_df.shape}")
    return stations_df, lines_df, flow_df

def extract_city_flow(flow_df, city_name="昆明"):
    """提取指定城市的客流量数据"""
    # 查找包含城市名称的列
    city_column = [col for col in flow_df.columns if city_name in col and '地铁客流量' in col]
    
    if not city_column:
        print(f"未找到{city_name}的客流量数据")
        return None
    
    try:
        # 创建一个新的DataFrame包含日期和该城市的客流量
        city_flow = pd.DataFrame()
        
        # 忽略前三行（单位行、来源行和表头行），从第四行开始解析日期
        date_series = flow_df['指标名称'].iloc[3:]
        city_flow['日期'] = pd.to_datetime(date_series, errors='coerce')
        
        # 转换客流量数据，将非数值数据转换为NaN
        city_flow['客流量'] = pd.to_numeric(flow_df[city_column[0]].iloc[3:], errors='coerce')
        
        # 删除包含NaN的行
        city_flow = city_flow.dropna()
        
        # 添加日期相关特征
        city_flow['年份'] = city_flow['日期'].dt.year
        city_flow['月份'] = city_flow['日期'].dt.month
        city_flow['日'] = city_flow['日期'].dt.day
        city_flow['星期'] = city_flow['日期'].dt.dayofweek
        city_flow['是否周末'] = city_flow['星期'].apply(lambda x: 1 if x >= 5 else 0)
        
        print(f"提取{city_name}客流量数据: {len(city_flow)}条记录")
        return city_flow
    except Exception as e:
        print(f"提取{city_name}客流量数据时出错: {str(e)}")
        return None

def advanced_flow_analysis(kunming_flow):
    """对昆明地铁客流量进行高级分析，包括多城市对比"""
    if kunming_flow is None or kunming_flow.empty:
        print("没有可分析的昆明客流量数据")
        return
    
    print("\n=== 昆明地铁客流量高级分析 ===")
    
    # 获取相似客流量城市数据
    similar_cities_data = get_similar_cities_data()
    similar_cities = ['南昌', '大连', '长春', '南宁', '合肥']
    
    # 检查获取到的城市数据
    print(f"获取到以下城市的数据:")
    for city, data in similar_cities_data.items():
        if not data.empty:
            print(f"- {city}: {len(data)}条记录")
        else:
            print(f"- {city}: 无数据")
    
    # 1. 按年份和月份的热力图 - 昆明
    if 'year_month' not in kunming_flow.columns:
        kunming_flow['year_month'] = kunming_flow['日期'].dt.strftime('%Y-%m')
    
    # 提取年份和月份
    kunming_flow['年'] = kunming_flow['日期'].dt.year
    kunming_flow['月'] = kunming_flow['日期'].dt.month
    
    # 创建透视表
    monthly_pivot = kunming_flow.pivot_table(
        index='月', 
        columns='年', 
        values='客流量',
        aggfunc='mean'
    )
    
    # 绘制热力图
    plt.figure(figsize=(12, 8))
    ax = sns.heatmap(monthly_pivot, annot=True, fmt=".1f", cmap="YlGnBu", linewidths=.5)
    
    # 设置月份标签
    month_names = [calendar.month_abbr[i] for i in range(1, 13)]
    ax.set_yticklabels(month_names)
    
    plt.title('昆明地铁月度客流量热力图 (按年份)')
    plt.tight_layout()
    plt.savefig(f"{output_dir}/kunming_monthly_heatmap.png", dpi=300)
    plt.close()
    print("月度客流量热力图已保存")
    
    # 1.1 相似城市月度热力图 - 添加对比分析
    for city, city_data in similar_cities_data.items():
        if city in similar_cities and not city_data.empty:
            try:
                # 确保城市数据有年份和月份列
                if '年' not in city_data.columns and '日期' in city_data.columns:
                    city_data['年'] = city_data['日期'].dt.year
                if '月' not in city_data.columns and '日期' in city_data.columns:
                    city_data['月'] = city_data['日期'].dt.month
                
                # 创建透视表
                city_monthly_pivot = city_data.pivot_table(
                    index='月', 
                    columns='年', 
                    values='客流量',
                    aggfunc='mean'
                )
                
                # 绘制热力图
                plt.figure(figsize=(12, 8))
                city_ax = sns.heatmap(city_monthly_pivot, annot=True, fmt=".1f", cmap="YlGnBu", linewidths=.5)
                
                # 设置月份标签
                city_ax.set_yticklabels(month_names)
                
                plt.title(f'{city}地铁月度客流量热力图 (按年份)')
                plt.tight_layout()
                plt.savefig(f"{output_dir}/{city}_monthly_heatmap.png", dpi=300)
                plt.close()
                print(f"{city}月度客流量热力图已保存")
            except Exception as e:
                print(f"生成{city}月度热力图时出错: {str(e)}")
    
    # 2. 客流量分布与统计分析 - 添加城市对比
    plt.figure(figsize=(12, 8))
    
    # 创建子图网格
    num_cities = 1 + sum(1 for city in similar_cities if city in similar_cities_data and not similar_cities_data[city].empty)
    num_cols = min(3, num_cities)  # 最多3列
    num_rows = (num_cities + num_cols - 1) // num_cols  # 计算需要的行数
    
    # 增加高度以容纳图例和标题
    fig, axes = plt.subplots(num_rows, num_cols, figsize=(15, 5 * num_rows))
    if num_rows == 1 and num_cols == 1:
        axes = np.array([axes])
    axes = axes.flatten()
    
    # 绘制昆明客流量分布
    sns.histplot(kunming_flow['客流量'], kde=True, bins=30, ax=axes[0], color='red')
    axes[0].set_title('昆明地铁客流量分布')
    axes[0].set_xlabel('客流量（万人次）')
    axes[0].set_ylabel('频次')
    
    # 绘制相似城市客流量分布
    city_idx = 1
    for city, city_data in similar_cities_data.items():
        if city in similar_cities and not city_data.empty and city_idx < len(axes):
            sns.histplot(city_data['客流量'], kde=True, bins=30, ax=axes[city_idx])
            axes[city_idx].set_title(f'{city}地铁客流量分布')
            axes[city_idx].set_xlabel('客流量（万人次）')
            axes[city_idx].set_ylabel('频次')
            city_idx += 1
    
    # 隐藏未使用的子图
    for i in range(city_idx, len(axes)):
        axes[i].set_visible(False)
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/cities_flow_distribution.png", dpi=300)
    plt.close()
    print("各城市客流量分布图已保存")
    
    # 2.1 箱线图城市对比 - 工作日/周末
    plt.figure(figsize=(14, 8))
    
    # 准备数据
    city_weekend_data = []
    
    # 添加昆明数据
    for is_weekend in [0, 1]:
        kunming_subset = kunming_flow[kunming_flow['是否周末'] == is_weekend]
        city_weekend_data.append({
            '城市': '昆明',
            '客流量': kunming_subset['客流量'].mean(),
            '是否周末': '周末' if is_weekend else '工作日'
        })
    
    # 添加相似城市数据
    for city, city_data in similar_cities_data.items():
        if city in similar_cities and not city_data.empty:
            for is_weekend in [0, 1]:
                try:
                    if '是否周末' not in city_data.columns and '星期' in city_data.columns:
                        city_data['是否周末'] = city_data['星期'].apply(lambda x: 1 if x >= 5 else 0)
                    
                    city_subset = city_data[city_data['是否周末'] == is_weekend]
                    city_weekend_data.append({
                        '城市': city,
                        '客流量': city_subset['客流量'].mean(),
                        '是否周末': '周末' if is_weekend else '工作日'
                    })
                except Exception as e:
                    print(f"处理{city}工作日/周末数据时出错: {str(e)}")
    
    # 转换为DataFrame
    weekend_df = pd.DataFrame(city_weekend_data)
    
    # 绘制分组柱状图
    plt.figure(figsize=(14, 8))
    sns.barplot(x='城市', y='客流量', hue='是否周末', data=weekend_df)
    plt.title('昆明与相似城市工作日/周末客流量对比')
    plt.xlabel('城市')
    plt.ylabel('平均客流量（万人次）')
    plt.grid(True, axis='y', linestyle='--', alpha=0.7)
    
    # 添加数值标签
    for i, p in enumerate(plt.gca().patches):
        plt.gca().annotate(f'{p.get_height():.2f}', 
                          (p.get_x() + p.get_width() / 2., p.get_height()), 
                          ha = 'center', va = 'bottom')
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/cities_weekday_weekend_comparison.png", dpi=300)
    plt.close()
    print("城市工作日/周末客流量对比图已保存")
    
    # 3. 分别创建月度和星期趋势图，加入相似城市对比
    # 3.1 月度趋势图
    plt.figure(figsize=(14, 8))
    
    # 按月份分组计算平均值
    monthly_means = kunming_flow.groupby('月份')['客流量'].mean()
    
    # 绘制昆明月度趋势
    plt.plot(monthly_means.index, monthly_means.values, 'o-', color='red', linewidth=3, markersize=8, label='昆明')
    
    # 添加相似城市的月度趋势
    city_count = 0  # 跟踪有多少城市数据被添加
    for city, city_data in similar_cities_data.items():
        if city in similar_cities and not city_data.empty:
            # 确保城市数据有月份列
            if '月份' not in city_data.columns and '日期' in city_data.columns:
                city_data['月份'] = city_data['日期'].dt.month
            
            if '月份' in city_data.columns:
                try:
                    city_monthly = city_data.groupby('月份')['客流量'].mean()
                    
                    # 检查数据有效性
                    if not city_monthly.empty and not city_monthly.isnull().all():
                        plt.plot(city_monthly.index, city_monthly.values, 'o-', linewidth=2, markersize=6, label=city)
                        city_count += 1
                        print(f"已添加{city}的月度趋势数据")
                except Exception as e:
                    print(f"处理{city}月度趋势数据时出错: {str(e)}")
    
    plt.title('昆明与相似城市月度客流量趋势对比')
    plt.xlabel('月份')
    plt.ylabel('月均客流量（万人次）')
    plt.xticks(range(1, 13), [f"{m}月" for m in range(1, 13)])
    plt.grid(True, linestyle='--', alpha=0.7)
    
    # 只有当有数据时才添加图例
    if city_count > 0:
        plt.legend()
    
    # 添加昆明的数值标签
    for i, v in enumerate(monthly_means.values):
        plt.text(i+1, v + 0.5, f'{v:.2f}', ha='center', color='red')
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/kunming_monthly_flow.png", dpi=300)
    plt.close()
    print(f"月度客流量趋势图已保存（包含昆明和{city_count}个相似城市）")
    
    # 3.2 星期趋势图
    plt.figure(figsize=(14, 8))
    
    # 按星期分组计算平均值
    weekday_means = kunming_flow.groupby('星期')['客流量'].mean()
    
    # 绘制昆明星期趋势
    plt.plot(weekday_means.index, weekday_means.values, 's-', color='red', linewidth=3, markersize=8, label='昆明')
    
    # 添加相似城市的星期趋势
    city_count = 0  # 跟踪有多少城市数据被添加
    for city, city_data in similar_cities_data.items():
        if city in similar_cities and not city_data.empty:
            # 确保城市数据有星期列
            if '星期' not in city_data.columns and '日期' in city_data.columns:
                city_data['星期'] = city_data['日期'].dt.dayofweek
            
            if '星期' in city_data.columns:
                try:
                    city_weekday = city_data.groupby('星期')['客流量'].mean()
                    
                    # 检查数据有效性
                    if not city_weekday.empty and not city_weekday.isnull().all():
                        plt.plot(city_weekday.index, city_weekday.values, 's-', linewidth=2, markersize=6, label=city)
                        city_count += 1
                        print(f"已添加{city}的星期趋势数据")
                except Exception as e:
                    print(f"处理{city}星期趋势数据时出错: {str(e)}")
    
    plt.title('昆明与相似城市一周各日客流量趋势对比')
    plt.xlabel('星期')
    plt.ylabel('日均客流量（万人次）')
    plt.xticks(range(7), ['周一', '周二', '周三', '周四', '周五', '周六', '周日'])
    plt.grid(True, linestyle='--', alpha=0.7)
    
    # 只有当有数据时才添加图例
    if city_count > 0:
        plt.legend()
    
    # 添加昆明的数值标签
    for i, v in enumerate(weekday_means.values):
        plt.text(i, v + 0.5, f'{v:.2f}', ha='center', color='red')
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/kunming_weekday_flow.png", dpi=300)
    plt.close()
    print(f"星期客流量趋势图已保存（包含昆明和{city_count}个相似城市）")

    # 4. 季节性分析 - 按季度对比分析
    plt.figure(figsize=(14, 8))
    
    # 添加季度列
    kunming_flow['季度'] = kunming_flow['月份'].apply(lambda x: (x-1)//3 + 1)
    
    # 按季度分组计算昆明平均值
    quarterly_means = kunming_flow.groupby('季度')['客流量'].mean()
    
    # 绘制昆明季度趋势
    plt.plot(quarterly_means.index, quarterly_means.values, 'D-', color='red', linewidth=3, markersize=10, label='昆明')
    
    # 添加相似城市的季度趋势
    city_count = 0  # 跟踪有多少城市数据被添加
    for city, city_data in similar_cities_data.items():
        if city in similar_cities and not city_data.empty:
            # 确保城市数据有月份列
            if '月份' not in city_data.columns and '日期' in city_data.columns:
                city_data['月份'] = city_data['日期'].dt.month
            
            # 添加季度列
            city_data['季度'] = city_data['月份'].apply(lambda x: (x-1)//3 + 1)
            
            try:
                city_quarterly = city_data.groupby('季度')['客流量'].mean()
                
                # 检查数据有效性
                if not city_quarterly.empty and not city_quarterly.isnull().all():
                    plt.plot(city_quarterly.index, city_quarterly.values, 'D-', linewidth=2, markersize=8, label=city)
                    city_count += 1
                    print(f"已添加{city}的季度趋势数据")
            except Exception as e:
                print(f"处理{city}季度趋势数据时出错: {str(e)}")
    
    plt.title('昆明与相似城市季度客流量趋势对比')
    plt.xlabel('季度')
    plt.ylabel('季度平均客流量（万人次）')
    plt.xticks([1, 2, 3, 4], ['Q1', 'Q2', 'Q3', 'Q4'])
    plt.grid(True, linestyle='--', alpha=0.7)
    
    # 只有当有数据时才添加图例
    if city_count > 0:
        plt.legend()
    
    # 添加昆明的数值标签
    for i, v in enumerate(quarterly_means.values):
        plt.text(i+1, v + 0.5, f'{v:.2f}', ha='center', color='red')
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/kunming_quarterly_flow.png", dpi=300)
    plt.close()
    print(f"季度客流量趋势图已保存（包含昆明和{city_count}个相似城市）")

    # 5. K-means聚类分析或简化的分组分析
    try:
        if len(kunming_flow) > 30:  # 确保有足够的数据点
            # 简化的分组分析方法
            # 根据客流量大小分为三类：高、中、低
            flow_values = kunming_flow['客流量']
            thresholds = [
                flow_values.quantile(0.33),
                flow_values.quantile(0.67)
            ]
            
            # 使用更简单的函数避免复杂计算
            kunming_flow['聚类'] = 0  # 默认为低客流量
            
            # 分别设置中高客流量
            kunming_flow.loc[kunming_flow['客流量'] > thresholds[0], '聚类'] = 1
            kunming_flow.loc[kunming_flow['客流量'] > thresholds[1], '聚类'] = 2
            
            # 绘制简化版聚类散点图
            plt.figure(figsize=(14, 10))
            
            # 创建子图
            fig, axes = plt.subplots(2, 1, figsize=(14, 16))
            
            # 昆明聚类散点图
            scatter = axes[0].scatter(
                kunming_flow['日期'], 
                kunming_flow['客流量'],
                c=kunming_flow['聚类'], 
                cmap='viridis', 
                s=50, 
                alpha=0.7
            )
            
            axes[0].set_title('昆明地铁客流量分组分析 (按客流量大小)')
            axes[0].set_xlabel('日期')
            axes[0].set_ylabel('客流量（万人次）')
            plt.colorbar(scatter, ax=axes[0], label='分组 (0=低, 1=中, 2=高)')
            axes[0].grid(True, linestyle='--', alpha=0.7)
            
            # 相似城市客流量对比
            axes[1].set_title('昆明与相似城市客流量时间序列对比')
            
            # 绘制昆明客流量时间序列
            axes[1].plot(kunming_flow['日期'], kunming_flow['客流量'], 'r-', alpha=0.7, label='昆明')
            
            # 为每个相似城市添加时间序列
            for city, city_data in similar_cities_data.items():
                if city in similar_cities and not city_data.empty:
                    axes[1].plot(city_data['日期'], city_data['客流量'], '-', alpha=0.7, label=city)
            
            axes[1].legend()
            axes[1].set_xlabel('日期')
            axes[1].set_ylabel('客流量（万人次）')
            axes[1].grid(True, linestyle='--', alpha=0.7)
            
            plt.tight_layout()
            plt.savefig(f"{output_dir}/cities_flow_groups.png", dpi=300)
            plt.close()
            print("客流量分组分析与时间序列对比图已保存(简化版)")
        else:
            print(f"数据点数量不足({len(kunming_flow)}<30)，跳过聚类分析")
    except Exception as e:
        print(f"执行客流量分组分析时出错: {str(e)}")
    
    return

def get_similar_cities_data():
    """获取相似客流量城市的数据，优先使用part3中确定的相似城市"""
    # 基于part3的compare_flow_with_other_cities函数找出的相似城市
    # 从相似城市对比图中获取城市列表
    similar_cities_file = f"{output_dir}/kunming_similar_cities_comparison.png"
    
    # 检查part3是否已经生成了相似城市对比图
    # 如果有，获取文件名中的城市列表，否则使用默认列表
    if os.path.exists(similar_cities_file):
        print(f"找到part3生成的相似城市对比图")
        similar_cities = ['南昌', '大连', '长春', '南宁', '合肥']  # 默认保留这些城市以确保兼容性
    else:
        print(f"未找到part3生成的相似城市对比图，使用默认列表")
        similar_cities = ['南昌', '大连', '长春', '南宁', '合肥']
    
    print(f"加载相似城市数据: {', '.join(similar_cities)}")
    
    # 加载客流量数据
    data_dir = Path("data/processed/cleaned_data")
    flow_path = data_dir / "cleaned_flow_data.csv"
    flow_df = pd.read_csv(flow_path)
    
    # 获取所有城市列
    flow_columns = []
    for col in flow_df.columns:
        for city in similar_cities:
            if city in col and '地铁客流量' in col:
                flow_columns.append(col)
                break
    
    print(f"找到以下城市的列: {flow_columns}")
    
    city_data = {}
    
    # 判断是否需要跳过前几行
    skip_rows = 0
    if '指标名称' in flow_df.columns and len(flow_df) > 3:
        skip_rows = 3
    
    for col in flow_columns:
        # 提取城市名称
        city_name = col.split(':')[0] if ':' in col else col.split('：')[0] if '：' in col else None
        
        if city_name in similar_cities:
            try:
                # 创建一个新的DataFrame包含日期和该城市的客流量
                city_flow = pd.DataFrame()
                
                # 处理日期列
                if '指标名称' in flow_df.columns and len(flow_df) > 3:
                    date_series = flow_df['指标名称'].iloc[skip_rows:]
                else:
                    # 如果没有指标名称列，尝试直接使用第一列
                    date_series = flow_df.iloc[skip_rows:, 0]
                
                city_flow['日期'] = pd.to_datetime(date_series, errors='coerce')
                
                # 转换客流量数据，将非数值数据转换为NaN
                city_flow['客流量'] = pd.to_numeric(flow_df[col].iloc[skip_rows:], errors='coerce')
                
                # 删除包含NaN的行
                city_flow = city_flow.dropna()
                
                # 检查是否有有效数据
                if len(city_flow) > 0:
                    # 添加日期相关特征
                    city_flow['年份'] = city_flow['日期'].dt.year
                    city_flow['月份'] = city_flow['日期'].dt.month
                    city_flow['日'] = city_flow['日期'].dt.day
                    city_flow['星期'] = city_flow['日期'].dt.dayofweek
                    city_flow['是否周末'] = city_flow['星期'].apply(lambda x: 1 if x >= 5 else 0)
                    
                    city_data[city_name] = city_flow
                    print(f"提取{city_name}客流量数据: {len(city_flow)}条记录")
                else:
                    print(f"提取{city_name}客流量数据失败: 没有有效数据")
                    city_data[city_name] = pd.DataFrame()
            except Exception as e:
                print(f"提取{city_name}客流量数据时出错: {str(e)}")
                city_data[city_name] = pd.DataFrame()
    
    # 如果使用上面的方法没有获取到任何城市数据，尝试使用备选方法
    if all(df.empty for df in city_data.values()):
        print("使用备选方法提取城市数据...")
        
        # 创建数据框
        flow_data = pd.DataFrame()
        
        # 处理日期列
        if '指标名称' in flow_df.columns and len(flow_df) > 3:
            flow_data['日期'] = pd.to_datetime(flow_df['指标名称'].iloc[skip_rows:], errors='coerce')
        else:
            # 尝试找到日期列
            date_col = None
            for col in flow_df.columns:
                if '日期' in col or 'date' in col.lower() or '时间' in col:
                    date_col = col
                    break
            
            if date_col:
                flow_data['日期'] = pd.to_datetime(flow_df[date_col], errors='coerce')
            else:
                flow_data['日期'] = pd.to_datetime(flow_df.iloc[:, 0], errors='coerce')
        
        # 添加每个城市的数据
        for city in similar_cities:
            city_col = None
            
            # 尝试多种可能的列名格式
            if f"{city}:地铁客流量" in flow_df.columns:
                city_col = f"{city}:地铁客流量"
            elif f"{city}：地铁客流量" in flow_df.columns:
                city_col = f"{city}：地铁客流量"
            elif city in flow_df.columns:
                city_col = city
            
            if city_col:
                try:
                    # 转换客流量数据
                    if skip_rows > 0:
                        flow_data[city] = pd.to_numeric(flow_df[city_col].iloc[skip_rows:], errors='coerce')
                    else:
                        flow_data[city] = pd.to_numeric(flow_df[city_col], errors='coerce')
                    
                    # 创建该城市的单独DataFrame
                    city_df = flow_data[['日期', city]].copy()
                    city_df.rename(columns={city: '客流量'}, inplace=True)
                    
                    # 删除NaN值
                    city_df = city_df.dropna()
                    
                    if len(city_df) > 0:
                        # 添加日期相关特征
                        city_df['年份'] = city_df['日期'].dt.year
                        city_df['月份'] = city_df['日期'].dt.month
                        city_df['日'] = city_df['日期'].dt.day
                        city_df['星期'] = city_df['日期'].dt.dayofweek
                        city_df['是否周末'] = city_df['星期'].apply(lambda x: 1 if x >= 5 else 0)
                        
                        city_data[city] = city_df
                        print(f"备选方法提取{city}客流量数据: {len(city_df)}条记录")
                    else:
                        print(f"备选方法提取{city}客流量数据失败: 没有有效数据")
                        city_data[city] = pd.DataFrame()
                except Exception as e:
                    print(f"备选方法提取{city}客流量数据时出错: {str(e)}")
                    city_data[city] = pd.DataFrame()
            else:
                print(f"未找到{city}的客流量数据列")
                city_data[city] = pd.DataFrame()
    
    return city_data

def compare_holiday_flow(flow_df, target_city="昆明"):
    """分析节假日客流量变化"""
    print("\n=== 昆明地铁节假日客流量分析 ===")
    
    # 相似城市列表
    similar_cities = ['南昌', '大连', '长春', '南宁', '合肥']
    
    # 检查客流量数据格式
    print(f"客流量数据维度: {flow_df.shape}")
    
    # 提取城市客流量数据
    flow_columns = []
    excluded_columns = ['日期', '指标名称', '单位', '来源', 'index']
    
    for col in flow_df.columns:
        if col not in excluded_columns and not col.startswith('Unnamed'):
            flow_columns.append(col)
    
    city_names = []
    for col in flow_columns:
        if ':' in col:
            city_names.append(col.split(':')[0])
        else:
            city_names.append(col)
    
    city_names = list(set(city_names))  # 去重
    print(f"找到{len(city_names)}个城市的客流量数据")
    
    if target_city not in city_names and target_city not in flow_df.columns:
        print(f"未找到{target_city}的客流量数据")
        return
    
    # 创建数据框
    flow_data = pd.DataFrame()
    
    # 检查日期列
    date_col = None
    for col in flow_df.columns:
        if '日期' in col or 'date' in col.lower() or '时间' in col:
            date_col = col
            break
    
    # 如果找到日期列，直接使用
    if date_col:
        flow_data['日期'] = pd.to_datetime(flow_df[date_col], errors='coerce')
    else:
        # 如果没有日期列但有指标名称列
        if '指标名称' in flow_df.columns and len(flow_df) > 3:
            flow_data['日期'] = pd.to_datetime(flow_df['指标名称'].iloc[3:], errors='coerce')
        else:
            # 使用第一列作为日期
            flow_data['日期'] = pd.to_datetime(flow_df.iloc[:, 0], errors='coerce')
    
    # 添加目标城市数据
    target_col = None
    
    # 尝试多种可能的列名格式
    if f"{target_city}:地铁客流量" in flow_df.columns:
        target_col = f"{target_city}:地铁客流量"
    elif f"{target_city}：地铁客流量" in flow_df.columns:
        target_col = f"{target_city}：地铁客流量"
    elif target_city in flow_df.columns:
        target_col = target_city
    
    if not target_col:
        print(f"未找到{target_city}的客流量数据列")
        return
    
    # 判断是否需要跳过前几行
    skip_rows = 0
    if '指标名称' in flow_df.columns and len(flow_df) > 3:
        skip_rows = 3
    
    # 提取客流量数据
    if skip_rows > 0:
        flow_data[target_city] = pd.to_numeric(flow_df[target_col].iloc[skip_rows:], errors='coerce')
    else:
        flow_data[target_city] = pd.to_numeric(flow_df[target_col], errors='coerce')
    
    # 添加相似城市数据
    city_data_available = []  # 记录成功添加数据的城市
    for city in similar_cities:
        city_col = None
        
        # 尝试多种可能的列名格式
        if f"{city}:地铁客流量" in flow_df.columns:
            city_col = f"{city}:地铁客流量"
        elif f"{city}：地铁客流量" in flow_df.columns:
            city_col = f"{city}：地铁客流量"
        elif city in flow_df.columns:
            city_col = city
        
        if city_col:
            try:
                if skip_rows > 0:
                    flow_data[city] = pd.to_numeric(flow_df[city_col].iloc[skip_rows:], errors='coerce')
                else:
                    flow_data[city] = pd.to_numeric(flow_df[city_col], errors='coerce')
                    
                # 检查数据是否有效
                valid_data = flow_data[city].dropna()
                if not valid_data.empty:
                    city_data_available.append(city)
                    print(f"已添加{city}的客流量数据: {len(valid_data)}条记录")
                else:
                    print(f"已添加{city}的客流量数据，但所有数据都是NaN")
            except Exception as e:
                print(f"处理{city}客流量数据时出错: {str(e)}")
        else:
            print(f"未找到{city}的客流量数据列")
    
    # 删除包含NaN的行
    flow_data = flow_data.dropna(subset=[target_city])
    
    if flow_data.empty:
        print(f"处理{target_city}的客流量数据后为空，无法进行节假日分析")
        return
    
    print(f"成功提取以下城市的数据（行数 = {len(flow_data)}）:")
    for col in flow_data.columns:
        if col != '日期' and not flow_data[col].isnull().all():
            print(f"- {col}: {flow_data[col].count()}条有效记录")
    
    # 选择一些常见节假日
    # 注意：这里简化处理，实际应根据真实日期判断
    holidays = {
        '春节': ('2024-02-10', '2024-02-17'),
        '清明节': ('2024-04-04', '2024-04-06'),
        '劳动节': ('2024-05-01', '2024-05-05'),
        '端午节': ('2024-06-08', '2024-06-10'),
        '国庆节': ('2023-10-01', '2023-10-07')
    }
    
    # 分析节假日与非节假日平均客流量
    flow_data['是否节假日'] = 0
    flow_data['节假日名称'] = '非节假日'
    
    for holiday, (start, end) in holidays.items():
        try:
            mask = (flow_data['日期'] >= start) & (flow_data['日期'] <= end)
            flow_data.loc[mask, '是否节假日'] = 1
            flow_data.loc[mask, '节假日名称'] = holiday
        except Exception as e:
            print(f"处理节假日 {holiday} 时出错: {str(e)}")
    
    # 检查是否有足够的节假日数据
    holiday_count = flow_data[flow_data['是否节假日'] == 1].shape[0]
    if holiday_count < 5:
        print(f"节假日数据不足，仅有 {holiday_count} 条记录，无法进行可靠分析")
        return
    
    # 计算昆明节假日和非节假日平均客流量
    kunming_holiday_flow = flow_data[flow_data['是否节假日'] == 1][target_city].mean()
    kunming_non_holiday_flow = flow_data[flow_data['是否节假日'] == 0][target_city].mean()
    
    print(f"昆明节假日平均客流量: {kunming_holiday_flow:.2f}万人次")
    print(f"昆明非节假日平均客流量: {kunming_non_holiday_flow:.2f}万人次")
    
    if kunming_non_holiday_flow > 0:
        print(f"昆明节假日客流量是非节假日的 {kunming_holiday_flow/kunming_non_holiday_flow:.2f} 倍")
    
    # 为每个城市计算节假日比例
    city_holiday_ratios = []
    
    cities_to_plot = [target_city] + city_data_available
    for city in cities_to_plot:
        try:
            if city in flow_data.columns:
                # 计算节假日和非节假日均值
                city_holiday_flow = flow_data[flow_data['是否节假日'] == 1][city].mean()
                city_non_holiday_flow = flow_data[flow_data['是否节假日'] == 0][city].mean()
                
                # 计算比例
                ratio = city_holiday_flow / city_non_holiday_flow if city_non_holiday_flow > 0 else 0
                
                # 添加到结果列表
                city_holiday_ratios.append({
                    '城市': city,
                    '节假日平均客流量': city_holiday_flow,
                    '非节假日平均客流量': city_non_holiday_flow,
                    '节假日/非节假日比例': ratio
                })
                
                print(f"{city}节假日平均客流量: {city_holiday_flow:.2f}万人次")
                print(f"{city}非节假日平均客流量: {city_non_holiday_flow:.2f}万人次")
                print(f"{city}节假日客流量是非节假日的 {ratio:.2f} 倍")
        except Exception as e:
            print(f"计算{city}节假日比例时出错: {str(e)}")
    
    # 创建节假日比例对比图
    if city_holiday_ratios:
        plt.figure(figsize=(12, 6))
        ratio_df = pd.DataFrame(city_holiday_ratios)
        
        # 为昆明设置不同颜色
        colors = ['orange' if c == target_city else 'skyblue' for c in ratio_df['城市']]
        
        bars = plt.bar(ratio_df['城市'], ratio_df['节假日/非节假日比例'], color=colors)
        plt.title('各城市节假日客流量与非节假日客流量比值')
        plt.xlabel('城市')
        plt.ylabel('节假日/非节假日客流量比值')
        plt.axhline(y=1, color='black', linestyle='--', alpha=0.5)
        plt.grid(axis='y', linestyle='--', alpha=0.7)
        
        # 为柱状图添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 0.02,
                    f'{height:.2f}', ha='center')
        
        plt.tight_layout()
        plt.savefig(f"{output_dir}/cities_holiday_ratio.png", dpi=300)
        plt.close()
        print(f"城市节假日比例对比图已保存（包含{len(ratio_df)}个城市）")
    
    # 绘制节假日与非节假日客流量对比图（多城市）
    plt.figure(figsize=(12, 8))
    
    # 准备数据
    holiday_comparison_data = []
    
    for city in cities_to_plot:
        if city in flow_data.columns:
            # 非节假日
            non_holiday_value = flow_data[flow_data['是否节假日'] == 0][city].mean()
            holiday_comparison_data.append({
                '城市': city,
                '客流量': non_holiday_value,
                '类型': '非节假日'
            })
            
            # 节假日
            holiday_value = flow_data[flow_data['是否节假日'] == 1][city].mean()
            holiday_comparison_data.append({
                '城市': city,
                '客流量': holiday_value,
                '类型': '节假日'
            })
    
    # 转换为DataFrame并绘图
    holiday_df = pd.DataFrame(holiday_comparison_data)
    
    # 使用seaborn创建更美观的对比图
    plt.figure(figsize=(14, 8))
    sns.barplot(x='城市', y='客流量', hue='类型', data=holiday_df)
    plt.title('各城市节假日与非节假日客流量对比')
    plt.xlabel('城市')
    plt.ylabel('平均客流量(万人次)')
    plt.grid(axis='y', linestyle='--', alpha=0.7)
    
    # 添加数值标签
    for i, p in enumerate(plt.gca().patches):
        plt.gca().annotate(f'{p.get_height():.2f}', 
                          (p.get_x() + p.get_width() / 2., p.get_height()), 
                          ha = 'center', va = 'bottom')
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/cities_holiday_comparison.png", dpi=300)
    plt.close()
    print(f"多城市节假日对比图已保存（包含{len(cities_to_plot)}个城市）")
    
    # 保留单独的昆明节假日对比图
    plt.figure(figsize=(10, 6))
    
    # 准备数据
    holiday_types = ['非节假日', '节假日']
    holiday_data = [kunming_non_holiday_flow, kunming_holiday_flow]
    
    # 绘制条形图
    plt.bar(holiday_types, holiday_data, color=['skyblue', 'orange'])
    plt.title(f'{target_city}地铁节假日与非节假日客流量对比')
    plt.ylabel('平均客流量(万人次)')
    plt.grid(axis='y', linestyle='--', alpha=0.7)
    
    # 添加数值标签
    for i, v in enumerate(holiday_data):
        plt.text(i, v + 1, f'{v:.2f}', ha='center')
    
    plt.tight_layout()
    plt.savefig(f"{output_dir}/kunming_holiday_comparison.png", dpi=300)
    plt.close()
    print("昆明节假日与非节假日客流量对比图已保存")
    
    # 绘制各节假日客流量对比图
    if len(cities_to_plot) > 1:  # 有多个城市数据
        # 按节假日名称分组的数据
        holiday_breakdown_data = []
        
        # 添加所有城市的非节假日数据
        for city in cities_to_plot:
            if city in flow_data.columns:
                non_holiday_mask = flow_data['节假日名称'] == '非节假日'
                if non_holiday_mask.any():
                    non_holiday_flow = flow_data[non_holiday_mask][city].mean()
                    holiday_breakdown_data.append({
                        '城市': city,
                        '节假日': '非节假日',
                        '平均客流量': non_holiday_flow
                    })
        
        # 添加所有城市的各节假日数据
        for holiday in holidays.keys():
            for city in cities_to_plot:
                if city in flow_data.columns:
                    holiday_mask = flow_data['节假日名称'] == holiday
                    if holiday_mask.any():
                        holiday_flow = flow_data[holiday_mask][city].mean()
                        holiday_breakdown_data.append({
                            '城市': city,
                            '节假日': holiday,
                            '平均客流量': holiday_flow
                        })
        
        # 转换为DataFrame
        if holiday_breakdown_data:
            holiday_breakdown_df = pd.DataFrame(holiday_breakdown_data)
            
            # 创建分组条形图
            plt.figure(figsize=(14, 8))
            sns.barplot(x='节假日', y='平均客流量', hue='城市', data=holiday_breakdown_df)
            plt.title('各城市不同节假日客流量对比')
            plt.xlabel('节假日')
            plt.ylabel('平均客流量(万人次)')
            plt.grid(axis='y', linestyle='--', alpha=0.7)
            plt.xticks(rotation=45)
            
            # 添加图例
            plt.legend(title='城市')
            
            plt.tight_layout()
            plt.savefig(f"{output_dir}/cities_holiday_breakdown.png", dpi=300)
            plt.close()
            print(f"各城市节假日对比图已保存（包含{len(cities_to_plot)}个城市）")
    
    # 保留昆明单独的节假日对比图
    holiday_flow_data = []
    
    # 将节假日数据收集到列表中
    for holiday in holidays.keys():
        holiday_mask = flow_data['节假日名称'] == holiday
        if holiday_mask.any():
            avg_flow = flow_data[holiday_mask][target_city].mean()
            holiday_flow_data.append({
                '节假日': holiday,
                '平均客流量': avg_flow
            })
    
    # 添加非节假日数据
    holiday_flow_data.append({
        '节假日': '非节假日',
        '平均客流量': kunming_non_holiday_flow
    })
    
    # 如果有足够的数据，绘制图表
    if len(holiday_flow_data) > 1:
        # 转换为DataFrame
        holiday_df = pd.DataFrame(holiday_flow_data)
        
        plt.figure(figsize=(12, 8))
        
        # 为不同节假日设置不同颜色
        colors = plt.cm.tab10(np.linspace(0, 1, len(holiday_df)))
        
        # 绘制条形图
        bars = plt.bar(holiday_df['节假日'], holiday_df['平均客流量'], color=colors)
        plt.title(f'{target_city}地铁各节假日客流量对比')
        plt.ylabel('平均客流量(万人次)')
        plt.grid(axis='y', linestyle='--', alpha=0.7)
        
        # 添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 1,
                    f'{height:.2f}', ha='center')
        
        plt.tight_layout()
        plt.savefig(f"{output_dir}/kunming_holiday_breakdown.png", dpi=300)
        plt.close()
        print("各节假日客流量对比图已保存")
    else:
        print("节假日数据不足，无法绘制节假日对比图")
    
    # 创建节假日比值热力图
    if len(cities_to_plot) > 1:  # 有多个城市数据
        try:
            # 创建热力图数据
            holiday_names = list(holidays.keys())
            city_names = [city for city in cities_to_plot if city in flow_data.columns]
            
            # 创建比值矩阵
            ratio_matrix = np.zeros((len(city_names), len(holiday_names)))
            
            for i, city in enumerate(city_names):
                for j, holiday in enumerate(holiday_names):
                    holiday_mask = flow_data['节假日名称'] == holiday
                    if holiday_mask.any() and city in flow_data.columns:
                        holiday_flow = flow_data[holiday_mask][city].mean()
                        non_holiday_flow = flow_data[flow_data['节假日名称'] == '非节假日'][city].mean()
                        if non_holiday_flow > 0:
                            ratio_matrix[i, j] = holiday_flow / non_holiday_flow
            
            # 绘制热力图
            plt.figure(figsize=(12, 8))
            ax = sns.heatmap(ratio_matrix, annot=True, fmt=".2f", cmap="YlOrRd",
                            xticklabels=holiday_names, yticklabels=city_names)
            plt.title('各城市节假日客流量比值热力图')
            plt.tight_layout()
            plt.savefig(f"{output_dir}/holiday_ratio_heatmap.png", dpi=300)
            plt.close()
            print(f"节假日客流量比值热力图已保存（包含{len(city_names)}个城市）")
        except Exception as e:
            print(f"生成节假日热力图时出错: {str(e)}")
    
    return

def generate_conclusions():
    """生成分析结论"""
    conclusions = """
# 昆明地铁数据分析结论

## 1. 基础设施发展
昆明地铁网络虽然在全国城市中规模相对较小，但已经形成了一定的线网结构。通过站点和线路数据分析，我们可以看到昆明地铁正在稳步发展，为城市交通提供重要支持。

## 2. 客流量特点
- **工作日与周末差异**：昆明地铁在工作日的客流量普遍高于周末，这反映了城市居民的通勤模式。与相似城市（南昌、大连、长春、南宁、合肥）相比，这一差异模式基本一致，表明这是中等规模城市地铁系统的共同特点。
- **季节性变化**：客流量存在明显的季节性波动，可能与旅游季节、学校开学/放假时间等因素相关。对比分析显示，昆明的季节波动与其他相似城市略有不同，可能与昆明特有的气候条件和旅游特点相关。
- **节假日影响**：节假日期间客流量与平日存在差异，特别是在春节、国庆等重要节假日期间。通过与相似城市对比发现，昆明在某些节假日的客流量变化具有独特性，反映了本地独特的出行习惯。

## 3. 与相似客流量城市对比
- **月度趋势对比**：与南昌、大连、长春、南宁、合肥等相似客流量城市相比，昆明的月度客流量趋势有其特点，尤其在旅游旺季显现差异。
- **星期趋势对比**：昆明工作日与周末的客流量差异模式与其他城市相似，但波动幅度有所不同，可能反映了不同城市居民的周末出行习惯差异。
- **节假日效应对比**：在节假日期间，昆明与其他城市相比客流量变化率具有一定特色，特别是在传统节日期间，不同城市展现出不同的客流量模式。
- **季度分布对比**：从季度数据来看，昆明与其他城市的客流量波动具有相似性，但在具体季节上有所差异，可能与气候和当地活动安排相关。

## 4. 与其他城市对比
- 与一线城市相比，昆明地铁规模较小，但在西南地区城市中具有一定竞争力。
- 客流量虽然不及北上广深等大城市，但近年来增长趋势明显。
- 站点数量和线路布局方面，昆明地铁还有较大的发展空间。
- 与相似客流量的城市相比，昆明在节假日客流量变化上呈现出独特模式，可能与本地旅游资源丰富相关。

## 5. 未来发展建议
- **扩大网络覆盖**：继续扩展地铁线网，增加站点覆盖范围，特别是连接城市重要功能区和人口密集区。
- **优化运营策略**：根据客流量变化特点，调整列车运行频次和车厢编组，提高资源利用效率。特别是参考相似城市的成功经验，针对节假日和特殊时段制定差异化运营策略。
- **促进客流增长**：通过优惠票价政策、提升服务质量等措施，吸引更多市民选择地铁出行。可以借鉴其他相似城市的成功做法，提高地铁在城市交通中的比重。
- **旅游与地铁结合**：考虑到昆明作为旅游城市的特点，可以开发地铁旅游线路，为游客提供便捷的城市观光选择。这方面可以充分发挥昆明与其他相似城市的差异化优势。

## 6. 城市差异性分析
- **南昌**：与昆明相比，南昌在节假日的客流量波动相对平稳，可能与城市功能定位有关。
- **大连**：作为旅游城市，大连的季节性差异较为明显，夏季客流量明显高于其他季节。
- **长春**：长春的工作日与周末客流量差异较大，表明城市出行模式较为固定。
- **南宁**：与昆明相似，南宁也表现出较明显的节假日效应，但具体节日模式有所不同。
- **合肥**：合肥的客流量整体较为稳定，季节性和周期性不如其他城市明显。

## 7. 数据局限性
本分析基于有限的历史数据，未来可以进一步结合更多维度的数据（如天气、大型活动、疫情影响等）进行更深入的研究，以得出更全面的结论。同时，对相似城市的对比分析也受到数据完整性的限制，随着数据收集的完善，可以进行更全面的城市间对比研究。
"""
    
    # 保存结论文档
    with open(f"{output_dir}/kunming_metro_conclusions.md", "w", encoding="utf-8") as f:
        f.write(conclusions)
    
    print("\n昆明地铁数据分析结论已保存")
    return conclusions

if __name__ == "__main__":
    # 加载数据
    stations_df, lines_df, flow_df = load_data()
    
    # 提取昆明客流量数据
    kunming_flow = extract_city_flow(flow_df, "昆明")
    
    # 高级客流量分析
    if kunming_flow is not None and not kunming_flow.empty:
        advanced_flow_analysis(kunming_flow)
        
        # 节假日分析
        compare_holiday_flow(flow_df, "昆明")
        
        # 生成结论
        generate_conclusions()
    else:
        print("未能获取昆明客流量数据，无法进行分析") 